package com.microlecture.utils;

import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.Assert;

import javax.xml.datatype.DatatypeConfigurationException;
import javax.xml.datatype.DatatypeFactory;
import javax.xml.datatype.XMLGregorianCalendar;
import java.sql.Timestamp;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;


public class DateUtil {

    public static final String PATTERN_STANDARD = "yyyy-MM-dd HH:mm:ss";

    public static final String PATTERN_DATE = "yyyy-MM-dd";

    public static final String SHORT_PATTERN_DATE = "yyyyMMdd";

    public static final String PATTERN_FULL_DATE = "yyyyMMddHHmmss";

    public static final String SHORT_HOUR_MIN_DATE = "HHmm";

    public static final String ZERO_STR = "0";

    private static final Logger LOG = LoggerFactory.getLogger(DateUtil.class);

    private static final long ONE_DAY_MSED = 1000 * 3600 * 24L;

    private static final int MIN_TO_MSEC = 60 * 1000;

    private DateUtil() {
    }

    public static String timestamp2String(Timestamp timestamp, String pattern) throws Exception {
        if (timestamp == null) {
            throw new Exception("timestamp null illegal");
        }
        String patternNew = pattern;
        if (pattern == null || "".equals(pattern)) {
            patternNew = PATTERN_STANDARD;
        }
        SimpleDateFormat sdf = new SimpleDateFormat(patternNew);
        return sdf.format(new Date(timestamp.getTime()));
    }

    public static String date2String(Date date, String pattern) {
        if (date == null) {
            return StringUtils.EMPTY;
        }
        String patternNew = pattern;
        if (StringUtils.isEmpty(pattern)) {
            patternNew = PATTERN_STANDARD;
        }
        SimpleDateFormat sdf = new SimpleDateFormat(patternNew);
        return sdf.format(date);
    }

    public static Timestamp currentTimestamp() {
        return new Timestamp(new Date().getTime());
    }

    public static String currentTimestamp2String(String pattern) throws Exception {
        return timestamp2String(currentTimestamp(), pattern);
    }

    public static Timestamp string2Timestamp(String strDateTime, String pattern) throws Exception {
        if (strDateTime == null || "".equals(strDateTime)) {
            throw new Exception("Date Time Null Illegal");
        }
        String patternNew = pattern;
        if (pattern == null || "".equals(pattern)) {
            patternNew = PATTERN_STANDARD;
        }

        SimpleDateFormat sdf = new SimpleDateFormat(patternNew);
        Date date = null;
        try {
            date = sdf.parse(strDateTime);
        } catch (ParseException e) {
            throw new Exception(e.toString());
        }
        return new Timestamp(date.getTime());
    }

    public static Date string2Date(String strDate, String pattern) throws Exception {
        if (strDate == null || "".equals(strDate)) {
            throw new Exception("str date null");
        }
        String patternNew = pattern;
        if (pattern == null || "".equals(pattern)) {
            patternNew = DateUtil.PATTERN_DATE;
        }
        SimpleDateFormat sdf = new SimpleDateFormat(patternNew);
        Date date = null;

        try {
            date = sdf.parse(strDate);
        } catch (ParseException e) {
            throw new Exception(e.toString());
        }
        return date;
    }

    public static String stringToYear(String strDest) throws Exception {
        if (strDest == null || "".equals(strDest)) {
            throw new Exception("str dest null");
        }

        Date date = string2Date(strDest, DateUtil.PATTERN_DATE);
        Calendar c = Calendar.getInstance();
        c.setTime(date);
        return String.valueOf(c.get(Calendar.YEAR));
    }

    public static String stringToMonth(String strDest) throws Exception {
        if (strDest == null || "".equals(strDest)) {
            throw new Exception("strDest null");
        }

        Date date = string2Date(strDest, DateUtil.PATTERN_DATE);
        Calendar c = Calendar.getInstance();
        c.setTime(date);
        int month = c.get(Calendar.MONTH);
        month = month + 1;
        if (month < 10) {
            return ZERO_STR + month;
        }
        return String.valueOf(month);
    }

    public static String stringToDay(String strDest) throws Exception {
        if (strDest == null || "".equals(strDest)) {
            throw new Exception("strDest is null");
        }

        Date date = string2Date(strDest, DateUtil.PATTERN_DATE);
        Calendar c = Calendar.getInstance();
        c.setTime(date);
        int day = c.get(Calendar.DAY_OF_MONTH);
        if (day < 10) {
            return ZERO_STR + day;
        }
        return Integer.toString(day);
    }

    public static Date getFirstDayOfMonth(Calendar c) {
        int year = c.get(Calendar.YEAR);
        int month = c.get(Calendar.MONTH);
        int day = 1;
        c.set(year, month, day, 0, 0, 0);
        return c.getTime();
    }

    public static Date getLastDayOfMonth(Calendar c) {
        int year = c.get(Calendar.YEAR);
        int month = c.get(Calendar.MONTH) + 1;
        int day = 1;
        if (month > 11) {
            month = 0;
            year = year + 1;
        }
        c.set(year, month, day - 1, 0, 0, 0);
        return c.getTime();
    }

    public static String date2GregorianCalendarString(Date date) throws Exception {
        if (date == null) {
            throw new Exception("Date is null");
        }
        long tmp = date.getTime();
        GregorianCalendar ca = new GregorianCalendar();
        ca.setTimeInMillis(tmp);
        try {
            XMLGregorianCalendar tXmlGregorianCalendar = DatatypeFactory.newInstance().newXMLGregorianCalendar(ca);
            return tXmlGregorianCalendar.normalize().toString();
        } catch (DatatypeConfigurationException e) {
            throw new Exception("Date is null:" + e);
        }

    }

    public static boolean compareDate(Date firstDate, Date secondDate) throws Exception {
        if (firstDate == null || secondDate == null) {
            throw new Exception("Date is null");
        }

        String strFirstDate = date2String(firstDate, PATTERN_DATE);
        String strSecondDate = date2String(secondDate, PATTERN_DATE);
        return StringUtils.equals(strFirstDate, strSecondDate);
    }

    @SuppressWarnings("deprecation")
    public static Date getStartTimeOfDate(Date currentDate) throws Exception {
        Assert.notNull(currentDate);
        String strDateTime = date2String(currentDate, PATTERN_DATE) + " 00:00:00";
        return string2Date(strDateTime, PATTERN_STANDARD);
    }

    @SuppressWarnings("deprecation")
    public static Date getEndTimeOfDate(Date currentDate) throws Exception {
        Assert.notNull(currentDate);
        String strDateTime = date2String(currentDate, PATTERN_DATE) + " 23:59:59";
        return string2Date(strDateTime, PATTERN_STANDARD);
    }

    public static long dateStrToLong(String[] symbols, String dateStr) {
        String newDateStr = dateStr;
        for (String symbol : symbols) {
            newDateStr = newDateStr.replaceAll(symbol, "");
        }

        return Long.parseLong(newDateStr);
    }

    public static long dateAddMonthToLong(int month, int dateType) throws Exception {
        Calendar c = Calendar.getInstance();
        c.add(Calendar.MONTH, month);
        String fmt;
        if (dateType == 1) {
            fmt = "yyyyMMddHHmm";
        } else {
            fmt = SHORT_PATTERN_DATE;
        }
        try {
            return Long.parseLong(date2String(c.getTime(), fmt));
        } catch (Exception e) {
            LOG.error("日期转化异常：", e);
            throw new Exception(e.toString());
        }
    }

    public static Date dateAddMin(Date date, int min) {
        Calendar c = Calendar.getInstance();
        c.setTime(date);
        c.add(Calendar.MINUTE, min);

        return c.getTime();
    }

    public static Date dateAddDay(Date date, int day) {
        Calendar c = Calendar.getInstance();
        c.setTime(date);
        c.add(Calendar.DAY_OF_MONTH, day);

        return c.getTime();
    }

    public static long getCurrtDateToLong(int dateType) throws Exception {
        Date date = new Date();
        String fmt;
        if (dateType == 1) {
            fmt = "yyyyMMddHHmm";
        } else {
            fmt = SHORT_PATTERN_DATE;
        }
        try {
            return Long.parseLong(date2String(date, fmt));
        } catch (Exception e) {
            LOG.error("getCurrtDateToLong异常：", e);
            throw new Exception(e.toString());
        }
    }

    public static int daysOfTwo(Date sDate, Date eDate) {
        Calendar aCalendar = Calendar.getInstance();

        aCalendar.setTime(sDate);
        int day1 = aCalendar.get(Calendar.DAY_OF_YEAR);
        aCalendar.setTime(eDate);
        int day2 = aCalendar.get(Calendar.DAY_OF_YEAR);

        return day2 - day1;
    }

    /**
     * 计算两个日期之间相差的天数
     * 
     * @param smdate
     *            较小的时间
     * @param bdate
     *            较大的时间
     * @return 相差天数
     * @throws ParseException
     */
    public static int daysBetween(Date smdate, Date bdate) throws ParseException {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        Date newsmdate = sdf.parse(sdf.format(smdate));
        Date newBdate = sdf.parse(sdf.format(bdate));
        Calendar cal = Calendar.getInstance();
        cal.setTime(newsmdate);
        long time1 = cal.getTimeInMillis();
        cal.setTime(newBdate);
        long time2 = cal.getTimeInMillis();
        long betweenDays = (time2 - time1) / ONE_DAY_MSED;

        return Integer.parseInt(String.valueOf(betweenDays));
    }

    /**
     * 从date得到yyyyMMdd
     * 
     * @param date
     * @return
     */
    public static String getFormatDate(Date date) {
        Date newDate = date;
        if (newDate == null) {
            newDate = new Date();
        }
        SimpleDateFormat sdf = new SimpleDateFormat(SHORT_PATTERN_DATE);
        return sdf.format(newDate);
    }

    /**
     * 检测时间是否在区间范围之内
     * 
     * @param date
     *            时间
     * @param startTime
     *            开始时间
     * @param endTime
     *            结束时间
     * @return 是否在区间范围之内
     */
    public static boolean checkTimeIsInRange(Date date, int startTime, int endTime) {
        int hour = getCalendarResult(date, Calendar.HOUR_OF_DAY);
        int minute = getCalendarResult(date, Calendar.MINUTE);
        String nowStr = String.valueOf(hour);
        if (minute / 10 == 0) {
            nowStr += ZERO_STR + minute;
        } else {
            nowStr += Integer.toString(minute);
        }
        int mixTime = Integer.parseInt(String.format("%s", nowStr));
        return startTime <= mixTime && mixTime <= endTime;
    }

    /**
     * 获取某个时间是星期几
     * 
     * @param date
     *            时间日期
     * @return 返回日期数字
     */
    public static int getDayOfWeek(Date date) {
        Date newDate = date;
        if (newDate == null) {
            newDate = new Date();
        }

        return getCalendarResult(newDate, Calendar.DAY_OF_WEEK);
    }

    private static int getCalendarResult(Date date, int type) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        return calendar.get(type);
    }

    /**
     * 日期加上/减去分钟得到新日期
     * 
     * @param sourceDate
     * @param minutes
     * @return
     */
    public static Date calculateDateWithMinutes(Date sourceDate, int minutes) {
        if (sourceDate == null)
            return null;
        return new Date(sourceDate.getTime() + minutes * MIN_TO_MSEC);
    }

    /**
     * 从yyyy-MM-dd HH:mm:ss格式字符串获取date
     * 
     * @param str
     * @return
     */
    public static Date getDateFromStr1(String str) {
        try {
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            return (sdf.parse(str));
        } catch (Exception e) {
            LOG.error("字符串转yyyy-MM-dd HH:mm:ss格式时间出错，str=" + str + ",e=", e);
            return null;
        }
    }

    public static int getShortHourMin() {
        Date newDate = new Date();
        SimpleDateFormat sdf = new SimpleDateFormat(SHORT_HOUR_MIN_DATE);
        return Integer.parseInt(sdf.format(newDate));
    }
}